(function() {
	// Caching main content
	var $content = $('#contentmain');
	
	/**
	 * Bot constructor
	 */
	var Bot = function() {
		var active = true,		// Active flag
			debug = true,		// Debug flag
			last,				// Last timer value
			lastArena,			// Last arena time
			currentPage,		// Current page handler
			justStarted = true,	// Just started flag
			log = [],			// Bot log
			mode = 'battle';	// Bot mode (@TODO)
		
		return {
			/**
			 * Start bot
			 * Triggers "bot-start" event
			 */
			start : function() {
				active = true;
				justStarted = true;
				$(this).trigger('bot-start');
				
				this.next();

				justStarted = false;
				
				return this;
			},
			
			/**
			 * Stop bot
			 * Triggers "bot-stop" event
			 */
			stop : function() {
				active = false;
				$(this).trigger('bot-stop');
				
				return this;
			},
			
			/**
			 * Toggle bot state
			 */
			toggle : function() {
				active ? this.stop() : this.start();
				
				return this;
			},
			
			/**
			 * Next bot frame
			 */
			next : function() {
				if (!active) {
					return this;
				}
			
				var current = $('#actiontimer').text(),
					self = this;

				isNaN(current) && (current = -1);
				
				if (justStarted || (last != current)) {
					if (+last < +current) {
						this.loaded();
					}
					
					if (current == '0.0') {
						this.ready();
					}
				}
				
				last = current;
				
				setTimeout(function() {
					self.next();
				}, 200);
				
				return this;
			},
			
			/**
			 * Try to define current page and execute its "loaded" handler
			 */
			loaded : function() {
				$(this).trigger('page-loaded');
				
				this.definePage();
				
				currentPage && currentPage.loaded && currentPage.loaded();
				
				return this;
			},
			
			/**
			 * Try to execute "ready" handler for the current page
			 */
			ready : function() {
				$(this).trigger('page-ready');
				
				!currentPage || !currentPage.check() && this.definePage();
				
				currentPage && currentPage.ready && currentPage.ready();
				
				return this;
			},
			
			/**
			 * Define current page and cache it
			 */
			definePage : function() {
				for (var i in Pages) {
					if (Pages[i].check && Pages[i].check()) {
						currentPage = Pages[i];
						
						break;
					}
				}
				
				return this;
			},
			
			/**
			 * Put items to the console if "debug" flag is set
			 *
			 * @param [args...] Any amount of arguments, all will be printed to console
			 */
			debug : function() {
				var args = Array.prototype.slice.call(arguments);
				args.unshift(new Date);
			
				debug && console.log.apply(console, args);
				
				return this;
			},
			
			/**
			 * Put a message to bot log
			 * If 1 argument given, it will be used as message
			 * If 2 arguments given, then first will be a category identifier, and the second is a message
			 */
			log : function() {
				var category = arguments.length == 1 ? 'general' : arguments[0],
					msg = arguments.length == 1 ? arguments[0] : arguments[1];
			
				log.push({
					date : new Date,
					category : category,
					msg : msg
				});
				
				return this;
			},
			
			/**
			 * Set stat value
			 *
			 * @param stat ID of element in bot stats panel
			 * @param value Value modifier
			 */
			setStat : function(stat, value) {
				var $fld = $('#' + stat),
					oldValue;
				
				if ($fld.size()) {
					oldValue = $fld.text().replace(/\D+/g, '');
					value = (+value) + (+oldValue);
					
					$fld.text(this.format(value));
				}
				
				return this;
			},
			
			/**
			 * Return bot "active" flag value
			 */
			isActive : function() {
				return active;
			},
			
			/**
			 * Format numeric value by adding commas
			 *
			 * @param {Number} value Input value
			 * 
			 * @returns {Number} Formatted value
			 */
			format : function(value) {
				value = value.toString().replace(/(\d{1,3}(?=(\d{3})+(?:\.\d|\b)))/g, '\$1,');
	
				return value;
			},
			
			/**
			 * Return bot log
			 *
			 * @returns {Array} Bot log
			 */
			getLog : function() {
				return log;
			},
			
			/**
			 * Get current mode
			 *
			 * @returns {String} Current mode
			 */
			getCurrentMode : function() {
				return mode;
			},
			
			/**
			 * Set new mode
			 *
			 * @param {String} newMode New mode ID
			 */
			setMode : function(newMode) {
				mode = newMode;
				
				return this;
			},
			
			/**
			 * Check if bot is ready for new arena
			 */
			isReadyForArena : function() {
				var now = new Date;
				
				return !lastArena || (lastArena.getHour() != now.getHour());
			},
			
			/**
			 * Set arena last enter time
			 */
			setNewArenaTime : function() {
				lastArena = new Date;
				
				return this;
			}
		};
	};
	
	/**
	 * Namespace that holds page handlers
	 */
	var Pages = {
		/**
		 * Main page
		 */
		'main' : {
			/**
			 * Check if this is a main page
			 *
			 * @returns {Boolean} "true" if this is a main page
			 */
			check : function() {
				return $('#mob, #contentselect').size() == 2;
			},
			
			/**
			 * "ready" state handler
			 */
			ready : function() {
				switch (bot.getCurrentMode()) {
					// Go to quests page
					case 'questComplete':
						$('#contentselect').val(5).change();
						break;
					// Select new quest mob
					case 'setNewMob':
						$('#mob').val($('#mob option[style]').val()).change();
						
						bot.setMode('battle');
						this.ready();
						
						break;
					// Default ("battle") mode
					default:
						var $btn = $('#battlebutton');
				
						$btn.size() && $btn[0].click();
				}
			}
		},
		
		/**
		 * ReCaptcha page
		 */
		'captcha' : {
			/**
			 * Check if this is a ReCaptcha page
			 *
			 * @returns {Boolean} "true" if this is a ReCaptcha page
			 */
			check : function() {
				return $('#recaptcha_div').size();
			},
			
			/**
			 * "loaded" state handler
			 */
			loaded : function() {
				bot.log('ReCaptcha');
				
				if (webkitNotifications.checkPermission() == 0) {
					webkitNotifications.createNotification('', 'TLR Bot', 'Check the ReCaptcha').show();
				}
			}
		},
	
		/**
		 * Battle page
		 */
		'battle' : {
			/**
			 * Check if this is a battle page
			 *
			 * @returns {Boolean} "true" if this is a battle page
			 */
			check : function() {
				return $('#battlebutton').val() == 'Battle Again';
			},
			
			/**
			 * "loaded" state handler
			 */
			loaded : function() {
				this.checkResults();
				this.checkLevelUp();
				this.checkLoot();
				this.checkQuestComplete();
				this.checkDungeonComplete();
			},
			
			/**
			 * "ready" state handler
			 */
			ready : function() {
				if (bot.getCurrentMode() == 'battle') {
					$('#battlebutton')[0].click();
				}
				else {
					$('input[value="Continue"]', $content)[0].click();
				}
			},
			
			/**
			 * Check battle results (win or defeat)
			 */
			checkResults : function() {
				bot.setStat($('span:contains("You defeated the")', $content).size() ? 'lineage-wins' : 'lineage-defeats', 1);
			},
			
			/**
			 * Check for levelup (and also for rune shards gift for that)
			 */
			checkLevelUp : function() {
				var $levelup = $(':contains("You gained a level")', $content);
				
				if (!$levelup.size()) {
					return false;
				}
				
				bot.setStat('lineage-levels', 1);
				
				// If some rune shards found
				$levelup.is(':contains("rune shard(s)")') && bot.setStat('loot-main-shards', $levelup.text().replace(/[^\d+]/g, ''));
			},
			
			/**
			 * Check for the loot
			 */
			checkLoot : function() {
				var $loot = $('#drop');
				
				if (!$loot.size()) {
					return;
				}
				
				var details = $('img:first', $loot).attr('src').split('/'),
					lootText = $loot.text(),
					lootType = details[2],
					statsMap = ['', 'health', 'attack', 'defence', 'accuracy', 'evasion', 'luck'],
					runesMap = ['', 'minor', 'major', 'ancient'],
					runeLevelMap = ['', 'common', 'uncommon', 'rare', 'legendary', 'epic', 'supreme'];
				
				bot.log('loot', lootText);
				console.dir($loot);
				
				// Do actions depending of loot type
				switch (details[2]) {
					// Stats up
					case 'stats':
						bot.setStat('main-' + statsMap[parseInt(details[3])], 1);
						break;
					// Rune found
					case 'runes':
						bot.setStat('loot-runes-' + runesMap[details[3]] + '-' + runeLevelMap[parseInt(details[4])], 1);
						break;
					// Key found
					case 'keys':
						bot.setStat('loot-keys-' + ['', '', 'green', 'blue', 'yellow', 'purple', 'red'][parseInt(details[3])], 1);
						break;
					// Other loot (shards, etc.)
					// We will define loot type and proceed to default step
					case '.png':
						////////////////// You found a tiny source of 4 rune shards! (8 Class Bonus)
						(lootText.indexOf('rune shards') >= 0) && (lootType = 'shards');
					// Main loot found or something else
					default:
						var pattern = /[\d\,]+/g,
							value = 0,
							match;
						
						while (match = pattern.exec(lootText)) {
							value += +match.toString().replace(/\D/g, '');
						}
						
						bot.setStat('loot-main-' + lootType, value);
				}
			},
			
			/**
			 * Check if quest is completed
			 */
			checkQuestComplete : function() {
				if ($(':contains("You have completed the quest")', $content).size()) {
					bot
						.log('quest', 'Quest complete')
						.setMode('completeQuest');
				}
			},
			
			checkDungeonComplete : function() {
				var $success = $('.success', $content);
				
				if ($success.is(':contains("You have found the treasure")')) {
					bot
						.log('dungeon', $success.text())
						.setMode('setNewMob')
						.setStat('lineage-dungeons', 1);
				}
			}
		},
		
		/**
		 * Quests page
		 */
		'quests' : {
			check : function() {
				return $('#contentselect').val() == 5;
			},
			
			loaded : function() {
				var $success = $('.success', $content);
				
				if ($success.size()) {
					bot.setStat('lineage-quests', 1);
					bot.log('quest', $success.text());
				}
			},
			
			ready : function() {
				var $btn;
				
				if (($btn = $('input[value="Collect Reward From Quest"]', $content)) && $btn.size()) {
					$btn[0].click();
				}
				else if (($btn = $('input[value="Generate Quest"]', $content)) && $btn.size()) {
					$btn[0].click();
				}
				else {
					bot.setMode('setNewMob');
					
					$('#contentselect').val(1).change();
				}
			}
		},
		
		/**
		 * Tradeskills page
		 */
		'tradeskills' : {
			check : function() {
				return $('#contentselect').val() == 4;
			},
			
			ready : function() {
				var $link = $('a:contains("for 10 seconds")', $content);
				
				if ($link.size()) {
					($link.attr('href') != '#') && $link.attr('onclick', $link.attr('href').replace('javascript:', '')).attr('href', '#');
					$link.click().remove();
					//$link[0].click();
				}
				else {
					var t = setInterval(function() {
						var $link = $('a:contains("Continue")', $content);
						
						if ($link.size()) {
							clearInterval(t);
							
							($link.attr('href') != '#') && $link.attr('onclick', $link.attr('href').replace('javascript:', '')).attr('href', '#');
							$link.click().remove();
							//$link[0].click();
						}
					}, 200);
				}
			}
		},
		
		/**
		 * Arena page
		 */
		'arena' : {
			check : function() {
				return $('#contentselect').val() == 10;
			},
			
			loaded : function() {
				if ($('.success', $content).size()) {
					bot.setNewArenaTime();
					bot.log('arena', 'Entered new arena');
					bot.setMode('battle');
				}
			},
			
			ready : function() {
				if (bot.getCurrentMode() == 'newArena') {
					$('a:contains("Join"):eq(1)')[0].click();
				}
				else {
					$('#contentselect').val(1).change();
				}
			}
		}
	};
	
	var bot = Bot();
	
	$(bot).bind('page-ready', function() {
		
	});
	
	/* ******************** UI ************************ */
	
	var $controls = $('<div id="bot-controls" class="panel"></div>')
		.insertAfter('#right3');
	
	var $startBtn = $('<input id="bot-start-btn" type="button" value="Start/Stop" />')
		.click(function() {
			bot.toggle();
		})
		.appendTo($controls);
	
	$(bot).bind({
		'bot-start' : function() {
			$startBtn.addClass('active');
		},
		'bot-stop' : function() {
			$startBtn.removeClass('active');
		}
	});
	
	var $statsPanel = $('<div id="bot-stats-panel" class="panel"> 				<div class="inner"> 					<div class="stats-block" id="main-block"> 						<h3>Main stats</h3> 						<dl> 							<dt>Health</dt> 							<dd id="main-health">0</dd> 							<dt>Attack</dt> 							<dd id="main-attack">0</dd> 							<dt>Defence</dt> 							<dd id="main-defence">0</dd> 							<dt>Accuracy</dt> 							<dd id="main-accuracy">0</dd> 							<dt>Evasion</dt> 							<dd id="main-evasion">0</dd> 							<dt>Luck</dt> 							<dd id="main-luck">0</dd> 						</dl> 					</div> 					 					<div class="stats-block" id="lineage-block"> 						<h3>Lineage</h3> 						<dl> 							<dt>Levels</dt> 							<dd id="lineage-levels">0</dd> 							<dt>Wins</dt> 							<dd id="lineage-wins">0</dd> 							<dt>Defeats</dt> 							<dd id="lineage-defeats">0</dd> 							<dt>Quests</dt> 							<dd id="lineage-quests">0</dd> 							<dt>Dungeons</dt> 							<dd id="lineage-dungeons">0</dd> 							<dt>Towers</dt> 							<dd id="lineage-towers">0</dd> 						</dl> 					</div> 					 					<div class="stats-block" id="loot-ts-masteries-block"> 						<h3>Masteries</h3> 						<dl> 							<dt>Foraging</dt> 							<dd id="loot-ts-masteries-foraging">0</dd> 							<dt>Woodcutting</dt> 							<dd id="loot-ts-masteries-woodcutting">0</dd> 							<dt>Mining</dt> 							<dd id="loot-ts-masteries-mining">0</dd> 							<dt>Quarrying</dt> 							<dd id="loot-ts-masteries-quarrying">0</dd> 						</dl> 					</div> 					 					<div class="stats-block" id="loot-ts-block"> 						<h3>Tradeskills</h3> 						<dl> 							<dt>Food</dt> 							<dd id="loot-ts-food">0</dd> 							<dt>Wood</dt> 							<dd id="loot-ts-wood">0</dd> 							<dt>Iron</dt> 							<dd id="loot-ts-iron">0</dd> 							<dt>Stone</dt> 							<dd id="loot-ts-stone">0</dd> 							<dt>Ingots</dt> 							<dd id="loot-ts-ingots">0</dd> 						</dl> 					</div> 					 					<div class="stats-block" id="loot-main-block"> 						<h3>Loot</h3> 						<dl> 							<dt>Gold</dt> 							<dd id="loot-main-gold">0</dd> 							<dt>Platinum</dt> 							<dd id="loot-main-platinum">0</dd> 							<dt>Diamonds</dt> 							<dd id="loot-main-diamonds">0</dd> 							<dt>Credits</dt> 							<dd id="loot-main-credits">0</dd> 							<dt>Shards</dt> 							<dd id="loot-main-shards">0</dd> 						</dl> 					</div> 					 					<div class="stats-block" id="loot-keys-block"> 						<h3>Keys</h3> 						<dl> 							<dt>Green (1 - 5)</dt> 							<dd id="loot-keys-green">0</dd> 							<dt>Blue (6 - 9)</dt> 							<dd id="loot-keys-blue">0</dd> 							<dt>Yellow (10 - 12)</dt> 							<dd id="loot-keys-yellow">0</dd> 							<dt>Purple (13 - 14)</dt> 							<dd id="loot-keys-purple">0</dd> 							<dt>Red (15)</dt> 							<dd id="loot-keys-red">0</dd> 						</dl> 					</div> 					 					<div class="stats-block" id="loot-runes-block"> 						<h3>Runes</h3> 						 						<div class="stats-block" id="loot-runes-minor-block"> 							<dl> 								<dt><img src="images/runes/1/3.png" alt="Common" title="Minor Common"></dt> 								<dd id="loot-runes-minor-common">0</dd> 								<dt><img src="images/runes/1/4.png" alt="Uncommon" title="Minor Uncommon"></dt> 								<dd id="loot-runes-minor-uncommon">0</dd> 								<dt><img src="images/runes/1/5.png" alt="Rare" title="Minor Rare"></dt> 								<dd id="loot-runes-minor-rare">0</dd> 								<dt><img src="images/runes/1/6.png" alt="Legendary" title="Minor Legendary"></dt> 								<dd id="loot-runes-minor-legendary">0</dd> 								<dt><img src="images/runes/1/7.png" alt="Epic" title="Minor Epic"></dt> 								<dd id="loot-runes-minor-epic">0</dd> 								<dt><img src="images/runes/1/8.png" alt="Supreme" title="Minor Supreme"></dt> 								<dd id="loot-runes-minor-supreme">0</dd> 							</dl> 						</div> 						 						<div class="stats-block" id="loot-runes-major-block"> 							<dl> 								<dt><img src="images/runes/2/3.png" alt="Common" title="Major Common"></dt> 								<dd id="loot-runes-major-common">0</dd> 								<dt><img src="images/runes/2/4.png" alt="Uncommon" title="Major Uncommon"></dt> 								<dd id="loot-runes-major-uncommon">0</dd> 								<dt><img src="images/runes/2/5.png" alt="Rare" title="Major Rare"></dt> 								<dd id="loot-runes-major-rare">0</dd> 								<dt><img src="images/runes/2/6.png" alt="Legendary" title="Major Legendary"></dt> 								<dd id="loot-runes-major-legendary">0</dd> 								<dt><img src="images/runes/2/7.png" alt="Epic" title="Major Epic"></dt> 								<dd id="loot-runes-major-epic">0</dd> 								<dt><img src="images/runes/2/8.png" alt="Supreme" title="Major Supreme"></dt> 								<dd id="loot-runes-major-supreme">0</dd> 							</dl> 						</div> 						 						<div class="stats-block" id="loot-runes-ancient-block"> 							<dl> 								<dt><img src="images/runes/3/3.png" alt="Common" title="Ancient Common"></dt> 								<dd id="loot-runes-ancient-common">0</dd> 								<dt><img src="images/runes/3/4.png" alt="Uncommon" title="Ancient Uncommon"></dt> 								<dd id="loot-runes-ancient-uncommon">0</dd> 								<dt><img src="images/runes/3/5.png" alt="Rare" title="Ancient Rare"></dt> 								<dd id="loot-runes-ancient-rare">0</dd> 								<dt><img src="images/runes/3/6.png" alt="Legendary" title="Ancient Legendary"></dt> 								<dd id="loot-runes-ancient-legendary">0</dd> 								<dt><img src="images/runes/3/7.png" alt="Epic" title="Ancient Epic"></dt> 								<dd id="loot-runes-ancient-epic">0</dd> 								<dt><img src="images/runes/3/8.png" alt="Supreme" title="Ancient Supreme"></dt> 								<dd id="loot-runes-ancient-supreme">0</dd> 							</dl> 						</div> 					</div> 				</div> 				<div class="clr"></div> 			</div>')
		.insertAfter('#header')
		.find('.inner');
	
	var $logPanel = $('<input type="button" value="Log" />')
		.click(function() {
			var $popup = $('#mainpopup');
			
			$popup.empty();
			
			$('<table cellspacing="0" cellpadding="0" width="775"><tbody><tr><td width="753"></td><td width="22" align="center"><a href="javascript:closeNav();" style="color: #222288"><img src="images/close.png" alt="X"></a></td></tr></tbody></table>').appendTo($popup);
			
			var $tbody = $('<table id="bot-log"><thead><tr><th>Time</th><th>Category</th><th>Event</th></tr></thead><tbody></tbody></table>')
				.appendTo($popup)
				.find('tbody');
			
			var log = bot.getLog();
			
			if (!log || !log.length) {
				$('<tr class="no-log"><td colspan="3">No log records</td></tr>').appendTo($tbody);
			}
			else {
				for (var i = 0; i < log.length; i++) {
					$('<tr><td>' + log[i].date.format('%H:%i:%s') + '</td><td class="log-category-' + log[i].category + '">' + log[i].category + '</td><td>' + log[i].msg + '</td></tr>').appendTo($tbody);
				}
			}
			
			$popup.css('visibility', 'visible');
		})
		.appendTo($controls);
	
	/* ************************************************ */
	
	bot.start();
	
	/* ******************* UTILS ********************** */
	
	Date.prototype.format = function(format) {
		var now = this;
		
		return format.replace(/%(\w)/g, function(match, placeholder) {
			var value;
			
			switch (placeholder) {
				case 'd':
					value = now.getDate();
					(value < 10) && (value = '0' + value);
					break;
				case 'm':
					value = now.getMonth() + 1;
					(value < 10) && (value = '0' + value);
					break;
				case 'Y':
					value = now.getFullYear();
					break;
				case 'H':
					value = now.getHours();
					(value < 10) && (value = '0' + value);
					break;
				case 'i':
					value = now.getMinutes();
					(value < 10) && (value = '0' + value);
					break;
				case 's':
					value = now.getSeconds();
					(value < 10) && (value = '0' + value);
					break;
			}
			
			return value;
		});
	}
})();
